package com.h3c.ptability.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.eos.common.custom.BusinessException;
import com.eos.common.util.IdWorker;
import com.h3c.ptability.bo.ElectronicSignBO;
import com.h3c.ptability.config.properties.ElectronicSignProperties;
import com.h3c.ptability.dto.electronicSign.*;
import com.h3c.ptability.entity.PtEsignDocFeature;
import com.h3c.ptability.entity.PtEsignDocTemplate;
import com.h3c.ptability.entity.PtEsignSceneTemplate;
import com.h3c.ptability.entity.PtOrgInfo;
import com.h3c.ptability.enums.NeedSignEnum;
import com.h3c.ptability.mapper.PtEsignDocTemplateMapper;
import com.h3c.ptability.mapstruct.PtEsignDocFeatureMapstruct;
import com.h3c.ptability.mapstruct.PtEsignDocTemplateMapstruct;
import com.h3c.ptability.service.*;
import com.h3c.ptability.support.PtEsignDtoPart;
import com.h3c.ptability.support.PtEsignTemplateParam;
import com.h3c.ptability.support.ReturnCodeEnum;
import com.h3c.ptability.utils.AsposeUtil;
import com.h3c.ptability.utils.WordUtil;
import com.h3c.ptability.vo.NameAndIdVO;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 电子签doc文件模板实现类
 *
 * @author chenyifan
 * @since 2022-05-19 10:46:25
 */
@Slf4j
@Service
@AllArgsConstructor
public class PtEsignDocTemplateServiceImpl extends ServiceImpl<PtEsignDocTemplateMapper, PtEsignDocTemplate> implements IPtEsignDocTemplateService {

    private final IPtEsignSceneTemplateService sceneTemplateService;

    private final IPtEsignDocFeatureService docFeatureService;

    private final ElectronicSignProperties electronicSignProperties;

    private final IPtOrgInfoService orgInfoService;

    private final CommService commService;


    @Override
    public List<PtEsignDocTemplate> getTemplateListBySceneId(String sceneId) {
        List<String> templateIdList = sceneTemplateService.list(new QueryWrapper<PtEsignSceneTemplate>().lambda()
                .eq(PtEsignSceneTemplate::getSceneId, sceneId)
        ).stream().map(PtEsignSceneTemplate::getTemplateId).collect(Collectors.toList());
        return list(new QueryWrapper<PtEsignDocTemplate>().lambda()
                .in(PtEsignDocTemplate::getTemplateId, templateIdList)
        );
    }

    @Override
    @SneakyThrows
    public File getPdfTemplate(PtEsignDocTemplate originDocTemplate, JSONObject userInfo){
        File originTemplate = FileUtil.writeBytes(originDocTemplate.getDocFile(),
                this.getClass().getResource("/").toString() + "/temp/word/" + IdUtil.randomUUID() + ".docx");
        String destPath = this.getClass().getResource("/").toString() + "/temp/word/" + IdUtil.randomUUID() + ".docx";
        String pdfPath = this.getClass().getResource("/").toString() + "/temp/pdf/" + IdUtil.randomUUID() + ".pdf";
        File destPathFile = FileUtil.touch(destPath);
        File pdfPathFile = FileUtil.touch(pdfPath);
        try {
            WordUtil.replaceTemplateWrite(originTemplate.getAbsolutePath(),
                    getReplaceMap(userInfo, JSONUtil.toList(JSONUtil.toJsonStr(originDocTemplate.getDocVariables()), PtEsignTemplateParam.class))
                    , destPathFile);
            FileUtil.del(originTemplate);
        } catch (Exception e) {
            log.error("填充word文档失败,报错信息:{}", e.getMessage());
            throw new BusinessException(ReturnCodeEnum.RC400.getCode(), "填充word文档失败,报错信息:" + e.getMessage());
        }
        //将word转成pdf
        AsposeUtil.wordToPdf(destPath, pdfPathFile);
        //删除word文件
        FileUtil.del(destPathFile);
        return pdfPathFile;
    }


    @Override
    @SneakyThrows
    public PtEsignDtoPart fixTemplateParam(PtEsignDocTemplate originDocTemplate, List<PtEsignDocFeature> esignDocFeature, JSONObject userInfo) {
        File pdfPathFile = getPdfTemplate(originDocTemplate, userInfo);
        //组装数据
        PtEsignDtoPart ptEsignDtoPart = new PtEsignDtoPart();
        SignDocs signDocs = new SignDocs();
        signDocs.setDocFilekey(pdfPathFile)
                .setDocName(originDocTemplate.getDocName().concat(".pdf"));


        SignDocDetails userSignDocDetails = new SignDocDetails();
        ArrayList<SignPos> userSignPosList = new ArrayList<>();
        ArrayList<Signers> signerList = new ArrayList<>();

        List<PtEsignDocFeature> orgSignFeature = esignDocFeature.stream().filter(s -> Objects.nonNull(s.getOrgInfoName())).collect(Collectors.toList());
        List<PtEsignDocFeature> userSignFeature = esignDocFeature.stream().filter(s -> Objects.isNull(s.getOrgInfoName())).collect(Collectors.toList());
        //组装用户签章数据
        for (PtEsignDocFeature ptEsignDocFeature : userSignFeature) {
            SignPos signPos = PtEsignDocFeatureMapstruct.INSTANCE.docFeature2SignPos(ptEsignDocFeature);
            SignDateInfos dateInfos = new SignDateInfos();
            dateInfos.setDateFormat("YYYY年MM月DD日");
            dateInfos.setFontSize("11");
            dateInfos.setPosPage(ptEsignDocFeature.getPosPage());
            dateInfos.setPosX(ptEsignDocFeature.getPosX());
            dateInfos.setPosY(Integer.parseInt(ptEsignDocFeature.getPosY()) - 40 + "");

            signPos.setSealType("0")
                    .setAddSignTime(true)
                    .setSignDateInfos(CollUtil.list(false, dateInfos));
            userSignPosList.add(signPos);
        }
        if (userSignFeature.size() > 0) {
            userSignDocDetails.setSignPosList(userSignPosList);
            userSignDocDetails.setDocFileName(originDocTemplate.getDocName().concat(".pdf"));
            Signers signers = new Signers();
            signers.setUniqueId(userInfo.getStr(ElectronicSignBO.ID_CARD))
                    .setAccountType("2")
                    .setSignOrder(userSignFeature.get(0).getSignOrder()+"")
                    .setAutoSign("false")
                    .setSignDocDetailsList(CollUtil.list(false, userSignDocDetails));
            signerList.add(signers);
        }
        //组装公司签章数据
        if (orgSignFeature.size() > 0) {
            //考虑到需要多个部门的公司盖章
            Map<String, List<PtEsignDocFeature>> map = orgSignFeature.stream().collect(
                    Collectors.groupingBy(
                            PtEsignDocFeature::getOrgInfoName
                    ));
            for (String s : map.keySet()) {
                Signers signers = new Signers();
                SignDocDetails orgSignDocDetails = new SignDocDetails();
                ArrayList<SignPos> orgSignPosList = new ArrayList<>();
                PtOrgInfo orgInfo;
                if ("人事范围".equals(s)) {
                    orgInfo = orgInfoService.getOne(new QueryWrapper<PtOrgInfo>().lambda()
                            .eq(PtOrgInfo::getSapCode, userInfo.getStr(ElectronicSignBO.PERSONNEL_RANGE_CODE))
                    );
                } else {
                    orgInfo = orgInfoService.getOne(new QueryWrapper<PtOrgInfo>().lambda()
                            .eq(PtOrgInfo::getOrgName, s)
                    );
                }
                orgSignDocDetails.setDocFileName(originDocTemplate.getDocName().concat(".pdf"));
                List<PtEsignDocFeature> ptEsignDocFeatures = map.get(s);
                for (PtEsignDocFeature ptEsignDocFeature : ptEsignDocFeatures) {
                    SignPos signPos = PtEsignDocFeatureMapstruct.INSTANCE.docFeature2SignPos(ptEsignDocFeature);
                    SignDateInfos dateInfos = new SignDateInfos();
                    dateInfos.setDateFormat("YYYY年MM月DD日");
                    dateInfos.setFontSize("11");
                    dateInfos.setPosPage(ptEsignDocFeature.getPosPage());
                    dateInfos.setPosX(ptEsignDocFeature.getPosX());
                    dateInfos.setPosY(Integer.parseInt(ptEsignDocFeature.getPosY()) - 40 + "");
                    signPos.setSealType("1")
                            .setAddSignTime(true)
                            .setSignDateInfos(CollUtil.list(false, dateInfos))
                            .setSealId(orgInfo.getSealId());
                    orgSignPosList.add(signPos);
                }
                orgSignDocDetails.setSignPosList(orgSignPosList);
                signers
                        .setAutoSign(String.valueOf(orgSignFeature.get(0).getSignSilentlyFlag()))
                        .setAccountType("1")
                        .setSignOrder(orgSignFeature.get(0).getSignOrder()+"")
                        .setAccountId(electronicSignProperties.getAccountId())
                        .setAuthorizationOrganizeId(orgInfo.getAuthorizationOrganizeId())
                        .setSignDocDetailsList(CollUtil.list(false, orgSignDocDetails));
                signerList.add(signers);
            }
        }
        ptEsignDtoPart.setSignDocs(signDocs);
        ptEsignDtoPart.setSignersList(signerList);
        return ptEsignDtoPart;
    }

    @Override
    public List<PtEsignDocTemplate> getTemplateListByIds(List<String> ids) {
        return list(new QueryWrapper<PtEsignDocTemplate>().lambda()
                .in(PtEsignDocTemplate::getTemplateId, ids)
        );
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTemplate(DocTemplateAndFeatureDTO templateAndFeatureDTO) throws Exception {
        PtEsignDocTemplate template = PtEsignDocTemplateMapstruct.INSTANCE.DTO2Entity(templateAndFeatureDTO.getDocTemplateDTO());
        for (PtEsignDocFeatureDTO docFeatureDTO : templateAndFeatureDTO.getDocFeatureDTOList()) {
            if (Objects.nonNull(docFeatureDTO.getOrgInfoName()) && StringUtils.isNotBlank(docFeatureDTO.getOrgInfoName())) {
                template.setNeedOrgSign(NeedSignEnum.NEED_SIGN);
            }
            if (Objects.isNull(docFeatureDTO.getOrgInfoName()) || StringUtils.isBlank(docFeatureDTO.getOrgInfoName())) {
                template.setNeedUserSign(NeedSignEnum.NEED_SIGN);
            }
        }
        template.setTemplateId(IdWorker.nextId() + "");
        template.setDocName(template.getDocName().substring(0, template.getDocName().indexOf(".")));
        File file = commService.getFile(templateAndFeatureDTO.getDocTemplateDTO().getDocId(), templateAndFeatureDTO.getDocTemplateDTO().getDocName(), "");
        template.setDocFile(FileUtil.readBytes(file));
        FileUtil.del(file);
        save(template);
        List<PtEsignDocFeature> ptEsignDocFeatures = PtEsignDocFeatureMapstruct.INSTANCE.dtoList2EntityList(templateAndFeatureDTO.getDocFeatureDTOList());
        ptEsignDocFeatures.forEach(s -> {
            s.setFeatureId(IdWorker.nextId() + "");
            s.setTemplateId(template.getTemplateId());
        });
        docFeatureService.saveBatch(ptEsignDocFeatures);
    }


    @Override
    public List<PtEsignDocTemplate> getTemplateListByTemplateList(List<PtEsignSceneTemplate> templateList) {
        List<String> templateIds = templateList.stream().map(PtEsignSceneTemplate::getTemplateId).collect(Collectors.toList());
        QueryWrapper<PtEsignDocTemplate> templateQW = new QueryWrapper<>();
        templateQW.lambda().in(PtEsignDocTemplate::getTemplateId, templateIds);
        return list(templateQW);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTemplate(String templateId) {
        removeById(templateId);
        docFeatureService.remove(new QueryWrapper<PtEsignDocFeature>().lambda()
                .eq(PtEsignDocFeature::getTemplateId, templateId)
        );
        sceneTemplateService.remove(new QueryWrapper<PtEsignSceneTemplate>().lambda()
                .eq(PtEsignSceneTemplate::getTemplateId, templateId)
        );
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTemplate(DocTemplateAndFeatureDTO templateAndFeatureDTO) throws Exception {
        PtEsignDocTemplate template = PtEsignDocTemplateMapstruct.INSTANCE.DTO2Entity(templateAndFeatureDTO.getDocTemplateDTO());
        template.setNeedOrgSign(NeedSignEnum.UN_NEED_SIGN);
        template.setNeedUserSign(NeedSignEnum.UN_NEED_SIGN);
        for (PtEsignDocFeatureDTO docFeatureDTO : templateAndFeatureDTO.getDocFeatureDTOList()) {
            if (Objects.nonNull(docFeatureDTO.getOrgInfoName()) && StringUtils.isNotBlank(docFeatureDTO.getOrgInfoName())) {
                template.setNeedOrgSign(NeedSignEnum.NEED_SIGN);
            }
            if (Objects.isNull(docFeatureDTO.getOrgInfoName()) || StringUtils.isBlank(docFeatureDTO.getOrgInfoName())) {
                template.setNeedUserSign(NeedSignEnum.NEED_SIGN);
            }
        }
        PtEsignDocTemplate docTemplate = getById(templateAndFeatureDTO.getDocTemplateDTO().getTemplateId());
        if (!StringUtils.equals(docTemplate.getDocId(), templateAndFeatureDTO.getDocTemplateDTO().getDocId())) {
            File file = commService.getFile(templateAndFeatureDTO.getDocTemplateDTO().getDocId(), templateAndFeatureDTO.getDocTemplateDTO().getDocName(), "");
            template.setDocFile(FileUtil.readBytes(file));
        }
        template.setDocName(template.getDocName().substring(0, template.getDocName().indexOf(".")));
        updateById(template);
        docFeatureService.remove(new QueryWrapper<PtEsignDocFeature>().lambda()
                .eq(PtEsignDocFeature::getTemplateId, template.getTemplateId())
        );
        List<PtEsignDocFeature> ptEsignDocFeatures = PtEsignDocFeatureMapstruct.INSTANCE.dtoList2EntityList(templateAndFeatureDTO.getDocFeatureDTOList());
        ptEsignDocFeatures.forEach(s -> {
            s.setFeatureId(IdWorker.nextId() + "");
            s.setTemplateId(template.getTemplateId());
        });
        docFeatureService.saveBatch(ptEsignDocFeatures);
    }


    /**
     * 获取填充word模板的map
     *
     * @param userInfo
     * @param docVariables
     * @return
     */
    private Map<String, String> getReplaceMap(JSONObject userInfo, List<PtEsignTemplateParam> docVariables) {
        if (Objects.isNull(docVariables) || docVariables.size() == 0) {
            return new HashMap<>(0);
        }
        HashMap<String, String> result = new HashMap<>(docVariables.size());
        for (PtEsignTemplateParam docVariable : docVariables) {
            Object obj = userInfo.getObj(docVariable.getFieldName());
            if(obj instanceof Long && StrUtil.containsAnyIgnoreCase(docVariable.getFieldName(),"date","time")){
                DateTime date = DateUtil.date(Long.parseLong(obj.toString()));
                result.put(docVariable.getParamName(), DateUtil.format(date,"yyyy/MM/dd"));
            }else{
                result.put(docVariable.getParamName(), userInfo.getStr(docVariable.getFieldName()));
            }
        }
        return result;
    }

    @Override
    public List<NameAndIdVO> getDocNameList(String appId) {
        LambdaQueryWrapper<PtEsignDocTemplate> queryWrapper = new QueryWrapper<PtEsignDocTemplate>().lambda();
        if(StringUtils.isNotBlank(appId)){
            queryWrapper.eq(PtEsignDocTemplate::getAppId,appId);
        }
        List<PtEsignDocTemplate> list = list(queryWrapper);
        return list.stream().map(o -> new NameAndIdVO(o.getTemplateId(), o.getDocName())).collect(Collectors.toList());
    }

}

